package com.coldlz.mmp.proxy;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import lombok.Getter;
import lombok.Setter;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

@Getter
@Setter
public class ProxyInfo {
    private boolean complete = false;
    private boolean connect;
    private String httpVersion;
    private volatile Protocol protocolName;
    private URI webSocketURI;
    private WebSocketVersion webSocketVersion;
    private List<Header> webSocketHttpHeaders;
    @JsonIgnore
    private byte[] handshakeInfo;
    @JsonIgnore
    private byte[] originalContent;
    private final List<String> contents = new ArrayList<>();
    private String host;
    private int port;
    private String remoteAddress;
    private String localAddress;

    public void parse(ChannelHandlerContext clientCtx, ByteBuf in) {
        int idx = in.readerIndex();
        int len = in.readableBytes();
        originalContent = new byte[len];
        in.readBytes(originalContent);
        in.readerIndex(idx);

        this.localAddress = clientCtx.channel().remoteAddress().toString();
        while (in.isReadable()) {
            if (complete) {
                break;
            }
            List<Byte> bytes = new ArrayList<>(128);
            while (true) {
                byte aByte = in.readByte();
                bytes.add(aByte);
                if (aByte == '\n' || in.readableBytes() == 0) {
                    byte[] line = new byte[bytes.size()];
                    for (int i = 0; i < bytes.size(); i++) {
                        line[i] = bytes.get(i);
                    }
                    // 这里的长度需要减去2，因为http协议中是以 \r\n 结尾
                    contents.add(new String(line, 0, bytes.size() - 2, Charset.defaultCharset()));
                    if (in.readableBytes() == 0) {
                        complete = true;
                    }
                    bytes.clear();
                    if (in.readableBytes() == 0) {
                        break;
                    }
                }
            }
        }
        if (contents.isEmpty()) {
            throw new CloseSignalException("未解析出内容");
        }
        String head = contents.get(0);
        String[] firstHeadArr = head.split(" ");
        if (firstHeadArr.length != 3) {
            // 非https代理
            throw new CloseSignalException("请求数据第一行异常：" + head);
        }
        String method = firstHeadArr[0];
        // https / ws / wss 这三种协议会触发connect请求
        if (method.equalsIgnoreCase(HttpMethod.CONNECT.name())) {
            this.connect = true;
            String uri = firstHeadArr[1];// eg: www.baidu.com:443   192/168.1.100:443
            int fi = uri.indexOf(":");
            if (fi >= 0) {
                if (uri.lastIndexOf(":") != fi) {
                    throw new CloseSignalException("请求地址异常,存在多个分隔符\":\"");
                }
                String[] uriSplit = uri.split(":");
                if (uriSplit.length > 2) {
                    throw new CloseSignalException("请求地址异常,存在多个分隔符\":\"");
                }
                this.host = uriSplit[0];
                this.port = Integer.parseInt(uriSplit[1]);
            } else {
                this.host = uri;
                this.port = 443;
            }
        } else {
            // 触发 http 请求
            this.connect = false;
            this.protocolName = Protocol.HTTP;
            String uri = firstHeadArr[1];//是一个完整的请求 eg: http://www.baidu.com/s?a=a
            if (!uri.startsWith("http")) {
                throw new CloseSignalException("请求地址异常,不是http开头");
            }
            try {
                URL url = URI.create(uri).toURL();
                this.host = url.getHost();
                if ((this.port = url.getPort()) == -1) {
                    this.port = url.getDefaultPort();
                }
            } catch (MalformedURLException e) {
                throw new CloseSignalException(e);
            }
        }
        this.httpVersion = firstHeadArr[2];
    }

}